package paper.query;

import java.util.regex.*;
import paper.db.Paper;
import java.util.Vector;
import java.util.Enumeration;

public class QueryBuilder {

	Vector dequotedTermVector; 
	String titleColumnName;
	String authorColumnName;
	String yearColumnName;

 	public QueryBuilder() {
        }

	public String queryHelp(){
		String queryhelp="<h2>Searching the database</h2> " +
					"<div class=\"help\">Either simply search titles by "+
					"adding keywords to the search (eg. <i>bayes</i> and <i>filter</i>) "+
					"or add date restrictions (eg. <i>year:2000</i>) or author details, like "+
					"<i>author:Flach</i> -- please note that the 'author:' key term is "+
					"case-sensitive. By contrast, normal keywords are not.<br/> "+
					"<br/>"+
					"You can also refine a search further using the 'NOT' term, or adding a <b>-</b> "+
					"before a keyword to restrict it. Put NOT clauses at the <i>end</i> of a search!"+
					"</div>";
		return queryhelp;
	}

    	public static String ltrim(String source) {
    	    	return source.replaceAll("^\\s+", "");
    	}

    	public static String rtrim(String source) {
        	return source.replaceAll("\\s+$", "");
    	}

    	public static String itrim(String source) {
    	    return source.replaceAll("\\b\\s{2,}\\b", " ");
    	}

    	public static String trim(String source) {
        	return itrim(ltrim(rtrim(source)));
    	}

	public String removeAll(String source,String removeMe){
		return source.replaceAll(removeMe,"");
	}

	public int findNearestPrevious(String testString, int startIdx, char findMe){
		int tmp=startIdx;
		while(tmp>-1){
			if  (testString.charAt(tmp)==findMe){
				break;
			}
			tmp--;
		}
		return tmp;
		
		
	}

	 public String safeSearchTermPrint(){
		 String returnVar="";
		for (Enumeration e = dequotedTermVector.elements(); e.hasMoreElements();)
			{
			String myString = (String) e.nextElement();
			myString=caseCleanUp(myString,false,false);
			myString=trim(myString);
			if(myString!=""){
				returnVar=returnVar+" "+myString;
			}
				
			}										 
		return returnVar;
	 }



     public Vector tokenizeString(String query, Vector response){
		// rewrite: do the NOT stuff after (pointlessly overcomplicated)
		query=trim(query);
		if(query.indexOf("\"")<0){
			String[] splitTerms=query.split(" ");
			for(int i=0;i<splitTerms.length;i++){
				if(splitTerms[i].length()>1){
					if(splitTerms[i].charAt(0)==('-')){
						response.addElement("not");
						splitTerms[i]=splitTerms[i].substring(1,splitTerms[i].length());
					}
					response.addElement(splitTerms[i]);
				}
			}
		}else {
			int firstIdx=query.indexOf("\"");
			int secondIdx=query.indexOf("\"",firstIdx+1);
			int testVar=secondIdx-firstIdx;

			if(testVar>-1 && testVar<2){
			} else if(testVar<0){
				query=removeAll(query,"\"");
				tokenizeString(query,response);						
			}else if (firstIdx<2){  
				response.addElement(query.substring(firstIdx+1,secondIdx));
				if(secondIdx<query.length()){
					tokenizeString(query.substring(secondIdx+1,query.length()),response);
				}	
			} else {
				if(query.charAt(firstIdx-1)==(' ')){
					tokenizeString(query.substring(0,firstIdx),response);
					response.addElement(query.substring(firstIdx+1,secondIdx));
					if(secondIdx<query.length()){
						tokenizeString(query.substring(secondIdx+1,query.length()),response);
					}
				} else {
					int thirdIdx=findNearestPrevious(query,firstIdx,' ');
					if(thirdIdx<0){
						if(query.substring(0,secondIdx).charAt(0)==('-')){
							response.addElement("not");
							response.addElement(query.substring(1,secondIdx));
						} else {
							response.addElement(query.substring(0,secondIdx));
						}
					} else {
					
						response.addElement(query.substring(0,thirdIdx));
						if(query.charAt(thirdIdx+1)==('-')){
							response.addElement("not");
							thirdIdx=thirdIdx+1;
						}
						response.addElement(query.substring(thirdIdx,secondIdx+1));
					}
					if(secondIdx<query.length()){
						tokenizeString(query.substring(secondIdx+1,query.length()),response);
					}
					
				}
			}
			
		}	 
		return response;
		
	}

	public static String tagCleanUp(String x){
	      StringBuilder sb = new StringBuilder();
       	 	char oc = ' ';
        	for (int i = 0; i < x.length(); i++) {
            char c = x.charAt(i);
            if (Character.isUpperCase(c)) {
                sb.append(c);
            } else if (c=='.'){
		sb.append(c); 
	    } else if (c=='-'){
		sb.append(c); 
	    } else if (c=='_'){
		sb.append(c); 
	    } else if (c==':'){
			sb.append(c);
			
		}else if (Character.isDigit(c)) {
                if (oc == 'a') {                 
                    sb.deleteCharAt(sb.length()-1);
                    while (i+1 < x.length() &&
                           Character.isDigit(x.charAt(i+1))) {
                        i++;
                    }
                    oc = ' ';
                    continue;
                }
                sb.append(c);
            } else if (Character.isLowerCase(c)) {
                sb.append(c);
            }
            oc = c;
        }
        return sb.toString();
	}

	public String caseCleanUp(String x,boolean removeLigatures,boolean removeColons){
	      StringBuilder sb = new StringBuilder();
       	 	char oc = ' ';
        	for (int i = 0; i < x.length(); i++) {
            char c = x.charAt(i);
            if (Character.isUpperCase(c)) {
                sb.append(c);
            } else if (c==' '){
		sb.append(c); 
	    } else if (c==':'&& !removeColons){
			sb.append(c);
			
		}else if (Character.isDigit(c)) {
                if (oc == 'a') {                 
                    sb.deleteCharAt(sb.length()-1);
                    while (i+1 < x.length() &&
                           Character.isDigit(x.charAt(i+1))) {
                        i++;
                    }
                    oc = ' ';
                    continue;
                }
                sb.append(c);
            } else if (Character.isLowerCase(c)) {
                if (oc == 'f' && removeLigatures) {
                    if (c == 'i') {
                        sb.deleteCharAt(sb.length()-1);
                        oc = ' ';
                        continue;
                    } else if (c == 'l') {
                        sb.deleteCharAt(sb.length()-1);
                        oc = ' ';
                        continue;
                    } else if (c == 'f') {
                        sb.deleteCharAt(sb.length()-1);
                        if (i != x.length() -1 &&
                            x.charAt(i+1) == 'i') {
                            i++;                       
                        }
                        oc = ' ';
                        continue;
                    }
                }
                sb.append(c);
            }
            oc = c;
        }
        return sb.toString();
	}

	public String[] getTableAndVar(String command){
		
		String[] tuple=command.split(":");	
		String[] returnVar=new String[2];
		if(tuple.length>1){
			if(tuple[0].equals("title")){
				returnVar[0]=this.titleColumnName;
				returnVar[1]=Paper.cleanUp(tuple[1]);
			} else if (tuple[0].equals("author")){
				returnVar[0]=this.authorColumnName;
				returnVar[1]=caseCleanUp(tuple[1],true,true); 
			} else if (tuple[0].equals("year")){
				returnVar[0]=this.yearColumnName;
				returnVar[1]=Paper.cleanUp(tuple[1]);
			} else {
				returnVar[0]=this.titleColumnName;
				returnVar[1]=Paper.cleanUp(tuple[1]);
			}	
		} else {
			returnVar[0]=this.titleColumnName;
			returnVar[1]=Paper.cleanUp(command);
		}

		return returnVar;
	}

	public String makeSQL(String query, String columnName, String authorColumnName, String yearColumnName){
		this.titleColumnName=columnName;
		this.authorColumnName=authorColumnName;
		this.yearColumnName=yearColumnName;

		if(query.equals("")){
		}	
		query=removeAll(query,"\\+");
		this.dequotedTermVector=new Vector<String>();
		
		dequotedTermVector=tokenizeString(query,dequotedTermVector);

		String outputString="";
		int expressionCount=0;
		String myTerm;
		

		for (Enumeration e = dequotedTermVector.elements(); e.hasMoreElements();)
		{
						
			String myString = (String) e.nextElement();
			myString=trim(myString);
			if(myString.equals("")||Paper.cleanUp(myString).equals("")){
			} else {
				if(myString.toLowerCase().equals("not")){
					try{
						myTerm=(String) e.nextElement();
						String[] tuple=getTableAndVar(myTerm);
						if(expressionCount<1){
							outputString= " "+tuple[0]+" NOT like '%"+tuple[1]+"%' ";
						} else {
							outputString=outputString+" AND "+tuple[0]+" NOT like '%"+tuple[1]+"%' ";	
						}
					} catch(Exception anerror){
					}
					
					expressionCount++;
				 } else if (myString.equals("and")){
				} else if (myString.equals("or")){
				}else {
					String[] tuple=getTableAndVar(myString);
					if(expressionCount<1){
						outputString=" "+tuple[0]+" LIKE '%"+tuple[1]+"%' ";
						expressionCount++;
					} else {
						outputString=outputString+" AND "+tuple[0]+" LIKE '%"+tuple[1]+"%' ";
						expressionCount++;
					}
				}
			} 
		}
		System.out.println("output: "+outputString);	
		return " WHERE "+outputString;	
	}


}

